package com.mjfeed.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;
import javax.persistence.LockModeType;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.mjfeed.dao.CartDao;
import com.mjfeed.dao.OrderDao;
import com.mjfeed.dao.OrderItemDao;
import com.mjfeed.dao.ProductDao;
import com.mjfeed.dto.api.OrderJSON;
import com.mjfeed.dto.api.OrderListJSON;
import com.mjfeed.entity.Admin;
import com.mjfeed.entity.Cart;
import com.mjfeed.entity.CartItem;
import com.mjfeed.entity.Member;
import com.mjfeed.entity.Order;
import com.mjfeed.entity.OrderItem;
import com.mjfeed.entity.PaymentMethod;
import com.mjfeed.entity.Product;
import com.mjfeed.entity.Receiver;
import com.mjfeed.entity.Shipping;
import com.mjfeed.entity.ShippingItem;
import com.mjfeed.entity.ShippingMethod;
import com.mjfeed.service.OrderService;
import com.mjfeed.util.Pagination;
import com.mjfeed.util.ParamBean;
import com.mjfeed.util.QueryCondition;

@Service("orderService")
public class OrderServiceImpl extends BaseServiceImpl implements OrderService {
	@Resource(name="cartDao")
	private CartDao cartDao;
	@Resource(name="orderDao")
	private OrderDao orderDao;
	@Resource(name="productDao")
	private ProductDao productDao;
	@Resource(name="orderItemDao")
	private OrderItemDao orderItemDao;

	@Transactional(readOnly = true)
	public Pagination<Order> getPagination(ParamBean paramBean) {
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		if (StringUtils.isNotBlank(paramBean.getKeyword())) {
			queryConditions.add(new QueryCondition(paramBean.getField(), QueryCondition.LK, paramBean.getKeyword()));
		}
		String orderBy = "order by id desc";
		Pagination<Order> pagination = (Pagination<Order>)getPagination(Order.class, queryConditions, orderBy, paramBean.getPage(), paramBean.getPageSize());
		pagination.setPageHtml(paramBean.getUrl());
		return pagination;
	}

	@Transactional(readOnly = true)
	public Pagination<Order> getPagination(ParamBean paramBean, Member member) {
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		if (StringUtils.isNotBlank(paramBean.getKeyword())) {
			String field = (paramBean.getField() == null || paramBean.getField().equals("")) ? "sn" : paramBean.getField();
			queryConditions.add(new QueryCondition(field, QueryCondition.LK, paramBean.getKeyword()));
		}
		//订单状态  1 待付款 2待发货 3待收货
		if (paramBean.getOrderStatus() > 0) { 
			if (paramBean.getOrderStatus() == 1) { 
				queryConditions.add(new QueryCondition("orderStatus <> 2 and orderStatus <> 3 and (paymentStatus = 0 or paymentStatus = 1)"));
			}
			if (paramBean.getOrderStatus() == 2) {
				queryConditions.add(new QueryCondition("orderStatus <> 2 and orderStatus <> 3 and paymentStatus = 2 and shippingStatus = 0"));
			}
			if (paramBean.getOrderStatus() == 3) {
				queryConditions.add(new QueryCondition("orderStatus <> 2 and orderStatus <> 3 and paymentStatus = 2 and shippingStatus = 2"));
			}
		}
		queryConditions.add(new QueryCondition("member", QueryCondition.EQ, member));
		String orderBy = "order by id desc";
		Pagination<Order> pagination = (Pagination<Order>)getPagination(Order.class, queryConditions, orderBy, paramBean.getPage(), paramBean.getPageSize());
		pagination.setPageHtml(paramBean.getUrl());
		return pagination;
	}
	
	@Transactional(readOnly = true)
	public Order build(Cart cart, Receiver receiver,
			PaymentMethod paymentMethod, ShippingMethod shippingMethod,
			boolean isInvoice, String invoiceTitle, String memo) {
		Assert.notNull(cart);
		Assert.notNull(cart.getMember());
		Assert.notEmpty(cart.getCartItems());

		Order order = new Order();
		order.setOrderStatus(1);
		order.setPaymentStatus(0);
		order.setShippingStatus(0);
		order.setFee(new BigDecimal(0));
		order.setOffsetAmount(new BigDecimal(0));
		order.setMemo(memo);
		order.setMember(cart.getMember());
		
		if (receiver != null) {
			order.setConsignee(receiver.getConsignee());
			order.setAreaName(receiver.getAreaName());
			order.setAddress(receiver.getAddress());
			order.setZipCode(receiver.getZipCode());
			order.setPhone(receiver.getPhone());
			order.setArea(receiver.getArea());
		}
		order.setPaymentMethod(paymentMethod);
		if (shippingMethod != null && paymentMethod != null && paymentMethod.getShippingMethods().contains(shippingMethod)) {
			BigDecimal freight = shippingMethod.calculateFreight(cart.getWeight());
			order.setFreight(freight);
			order.setShippingMethod(shippingMethod);
		} else {
			order.setFreight(new BigDecimal(0));
		}
		List<OrderItem> orderItems = order.getOrderItems();
		for (CartItem cartItem : cart.getCartItems()) {
			if (cartItem != null && cartItem.getProduct() != null) {
				Product product = cartItem.getProduct();
				OrderItem orderItem = new OrderItem();
				orderItem.setSn(product.getSn());
				orderItem.setName(product.getName());
				orderItem.setFullName((product.getFullName() == null) ? product.getName() : "");
				orderItem.setPrice(cartItem.getPrice());
				orderItem.setWeight(product.getWeight());
				orderItem.setThumbnail(product.getThumbnail());
				orderItem.setIsGift(false);
				orderItem.setQuantity(cartItem.getQuantity());
				orderItem.setShippedQuantity(0);
				orderItem.setReturnQuantity(0);
				orderItem.setProduct(product);
				orderItem.setOrder(order);
				orderItems.add(orderItem);
			}
		}
		if (isInvoice) {
			order.setIsInvoice(true);
			order.setInvoiceTitle(invoiceTitle);
		} else {
			order.setIsInvoice(false);
		}
		order.setTax(new BigDecimal(0));

		if (paymentMethod != null && paymentMethod.getTimeout() != null && order.getPaymentStatus() == 0) {
			order.setExpire(DateUtils.addMinutes(new Date(), paymentMethod.getTimeout()));
		}
		return order;
	}

	@Transactional
	public Order create(Cart cart, Receiver receiver,
			PaymentMethod paymentMethod, ShippingMethod shippingMethod,
			boolean isInvoice, String invoiceTitle,	String memo, Admin operator) {
		Assert.notNull(cart);
		Assert.notNull(cart.getMember());
		Assert.notEmpty(cart.getCartItems());
		Assert.notNull(receiver);
		Assert.notNull(paymentMethod);
		Assert.notNull(shippingMethod);

		Order order = build(cart, receiver, paymentMethod, shippingMethod, isInvoice, invoiceTitle, memo);

		order.setSn(DateFormatUtils.format(new Date(), "yyyyMMddHHmmss"));
		if (paymentMethod.getMethod() == 0) {
			order.setLockExpire(DateUtils.addSeconds(new Date(), 20));
			order.setOperator(operator);
		}

		order.setIsAllocatedStock(false);
		order.setAmountPaid(new BigDecimal(0));
		order.setCouponDiscount(new BigDecimal(0));
		order.setPoint(0l);
		order.setPromotionDiscount(new BigDecimal(0));
		save(order);
		delete(cart);
		return order;
	}
	
	@Transactional
	public void shipping(Order order, Shipping shipping, Admin operator) {
		Assert.notNull(order);
		Assert.notNull(shipping);
		Assert.notEmpty(shipping.getShippingItems());

		orderDao.lock(order, LockModeType.PESSIMISTIC_WRITE);
		shipping.setOrder(order);
		orderDao.save(shipping);
		for (ShippingItem shippingItem : shipping.getShippingItems()) {
			OrderItem orderItem = order.getOrderItem(shippingItem.getSn());
			if (orderItem != null) {
				Product product = orderItem.getProduct();
				productDao.lock(product, LockModeType.PESSIMISTIC_WRITE);
				if (product != null) {
					if (product.getStock() != null) {
						product.setStock(product.getStock() - shippingItem.getQuantity());
						if (order.getIsAllocatedStock()) {
							product.setAllocatedStock(product.getAllocatedStock() - shippingItem.getQuantity());
						}
					}
					productDao.update(product);
					orderDao.flush();
				}
				orderItemDao.lock(orderItem, LockModeType.PESSIMISTIC_WRITE);
				orderItem.setShippedQuantity(orderItem.getShippedQuantity() + shippingItem.getQuantity());
			}
		}
		if (order.getShippedQuantity() >= order.getQuantity()) {
			order.setShippingStatus(2);
			order.setIsAllocatedStock(false);
		} else if (order.getShippedQuantity() > 0) {
			order.setShippingStatus(1);
		}
		order.setExpire(null);
		orderDao.update(order);
	}
	
	@Transactional(readOnly=true)
	public OrderItem getOrderItem(Order order, Product product) {
		List<QueryCondition> queryConditions = new ArrayList<QueryCondition>();
		queryConditions.add(new QueryCondition("order", QueryCondition.EQ, order));
		queryConditions.add(new QueryCondition("product", QueryCondition.EQ, product));
		return (OrderItem)getSingleResult(OrderItem.class, queryConditions);
	}

	@Override
	public OrderListJSON searchToJSON(Pagination<Order> pagination) {
		if (pagination != null) {
			OrderListJSON orderList = new OrderListJSON();
			orderList.setCurrentPage(pagination.getCurrentPage());
			orderList.setPageSize(pagination.getPageSize());
			orderList.setRecordCount(pagination.getRecordCount());
			orderList.setPageCount(pagination.getPageCount());
			orderList.setPrePage(pagination.getPrePage());
			orderList.setNextPage(pagination.getNextPage());
			orderList.setHasPrePage(pagination.isHasPrePage());
			orderList.setHasNextPage(pagination.isHasNextPage());
			List<OrderJSON> recordList = new ArrayList<OrderJSON>();
			for (Order order : pagination.getRecordList()) {
				OrderJSON orderJson = new OrderJSON();
				orderJson.setOrderId(order.getId());
				orderJson.setSn(order.getSn());
				orderJson.setOrderStatus(order.getOrderStatus());
				orderJson.setPaymentStatus(order.getPaymentStatus());
				orderJson.setShippingStatus(order.getShippingStatus());
				orderJson.setAmount(order.getAmount());
				List<OrderJSON.OrderItem> orderItems = new ArrayList<OrderJSON.OrderItem>();
				for (OrderItem orderItem: order.getOrderItems()) {
					OrderJSON.OrderItem orderItemJson = new OrderJSON.OrderItem();
					orderItemJson.setProductId(orderItem.getProduct().getId());
					orderItemJson.setSn(orderItem.getSn());
					orderItemJson.setName(orderItem.getName());
					orderItemJson.setPrice(orderItem.getPrice());
					orderItemJson.setQuantity(orderItem.getQuantity());
					orderItemJson.setWeight(orderItem.getWeight());
					orderItemJson.setThumbnail(orderItem.getThumbnail());
					orderItems.add(orderItemJson);
				}
				orderJson.setOrderItems(orderItems);
				recordList.add(orderJson);
			}
			orderList.setRecordList(recordList);
			return orderList;
		}
		return null;
	}

	@Override
	public OrderJSON beanToJSON(Order order) {
		if (order != null) {
			OrderJSON orderJson = new OrderJSON();
			orderJson.setOrderId(order.getId());
			orderJson.setSn(order.getSn());
			orderJson.setOrderStatus(order.getOrderStatus());
			orderJson.setPaymentStatus(order.getPaymentStatus());
			orderJson.setShippingStatus(order.getShippingStatus());
			orderJson.setAmount(order.getAmount());
			List<OrderJSON.OrderItem> orderItems = new ArrayList<OrderJSON.OrderItem>();
			for (OrderItem orderItem: order.getOrderItems()) {
				OrderJSON.OrderItem orderItemJson = new OrderJSON.OrderItem();
				orderItemJson.setProductId(orderItem.getProduct().getId());
				orderItemJson.setSn(orderItem.getSn());
				orderItemJson.setName(orderItem.getName());
				orderItemJson.setPrice(orderItem.getPrice());
				orderItemJson.setQuantity(orderItem.getQuantity());
				orderItemJson.setWeight(orderItem.getWeight());
				orderItemJson.setThumbnail(orderItem.getThumbnail());
				orderItems.add(orderItemJson);
			}
			orderJson.setOrderItems(orderItems);
			return orderJson;
		}
		return null;
	}

	@Transactional(readOnly = true)
	public long getNotPayCount(Member member) {
		List<Order> orderList = getByJpql("from Order o where o.orderStatus <> 2 and o.orderStatus <> 3 and (o.paymentStatus = 0 or o.paymentStatus = 1) and o.member.id=?", new Object[]{member.getId()});
		if (orderList != null && orderList.size() > 0) {
			return orderList.size();
		}
		return 0;
	}

	@Transactional(readOnly = true)
	public long getNotShipCount(Member member) {
		List<Order> orderList = getByJpql("from Order o where o.orderStatus <> 2 and o.orderStatus <> 3 and o.paymentStatus = 2 and o.shippingStatus = 0 and o.member.id=?", new Object[]{member.getId()});
		if (orderList != null && orderList.size() > 0) {
			return orderList.size();
		}
		return 0;
	}

	@Transactional(readOnly = true)
	public long getNotReceiveCount(Member member) {
		List<Order> orderList = getByJpql("from Order o where o.orderStatus <> 2 and o.orderStatus <> 3 and o.paymentStatus = 2 and o.shippingStatus = 2 and o.member.id=?", new Object[]{member.getId()});
		if (orderList != null && orderList.size() > 0) {
			return orderList.size();
		}
		return 0;
	}
}
